;/////////////////////////////////////////////////////////////;
;                                                             ;
;                 SimpleDX11 Model Procedures                 ;
;                                                             ;
;                                                             ;
;                   (c) 2013 SimpleDX Team                    ;
;                                                             ;
;                         License: MIT                        ;
;                                                             ;
;/////////////////////////////////////////////////////////////;


;-//    Private structures    //
Structure Primitive_UV
  List UV.XMFLOAT2()
EndStructure


Structure Primitive_Template
  *vTable
  *p.Primitive
  
  List VertexList.XMFLOAT4()
  List NormalList.XMFLOAT4()
  List ColorList.D3DXCOLOR()
  List UVMapList.Primitive_UV()
  List IndexList.l()
  
  IsNormal.b
  IsColor.b
  IsUVMap.b
  
  Stride.l
  
  Topology.l
EndStructure


;-//    Constructor    //
; Vertex format is Vertex - Normals - Color - Texture 
Procedure New_Primitive(Flags.l = #Null)
  Protected *this.Primitive_Template
 
  *this = AllocateMemory(SizeOf(Primitive_Template))
  InitializeStructure(*this, Primitive_Template)
  
  If *this
    *this\vTable = ?Primitive_Class    
    *this\p = *this
    
    *this\Stride = SizeOf(XMFLOAT4)
    
    If Flags & #SDX_Vertex_Normals  : *this\IsNormal  = #True : *this\Stride + SizeOf(XMFLOAT4)  : EndIf
    If Flags & #SDX_Vertex_Colors   : *this\IsColor   = #True : *this\Stride + SizeOf(D3DXCOLOR) : EndIf
    If Flags & #SDX_Vertex_UVMap    : *this\IsUVMap   = #True : *this\Stride + SizeOf(XMFLOAT2)  : EndIf
    
    *this\Topology = #D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST
   
    ProcedureReturn *this
  EndIf  
  ProcedureReturn #False
EndProcedure





;-//    Public procedures    //
; Add a vertex to the primitive
Procedure Primitive_AddVertex(*this.Primitive_Template, x.f, y.f, z.f)
  
  AddElement(*this\VertexList())  
  *this\VertexList()\x = x
  *this\VertexList()\y = y
  *this\VertexList()\z = z
  *this\VertexList()\w = 1.0    
    
  If *this\IsNormal : AddElement(*this\NormalList()) : EndIf  
  If *this\IsColor  : AddElement(*this\ColorList())  : EndIf
  If *this\IsUVMap  
  If Not ListSize(*this\UVMapList()) : AddElement(*this\UVMapList()) : EndIf
  
  ResetList(*this\UVMapList())
  While NextElement(*this\UVMapList())        
      AddElement(*this\UVMapList()\UV())
  Wend
  EndIf
  
  ProcedureReturn *this\VertexList()
EndProcedure

; Add a array of vertices to the Primitive
Procedure Primitive_AddVerticesArray(*this.Primitive_Template,  *Vertices, VertexCount.l = #Null, Offset.l = #Null)
  
  Protected x.l, i.l
  
  For x = 0 To VertexCount
    AddElement(*this\VertexList())  
    *this\VertexList()\x = PeekF(*Vertices + (x * Offset))
    *this\VertexList()\y = PeekF(*Vertices + (x * Offset) + SizeOf(Float))
    *this\VertexList()\z = PeekF(*Vertices + (x * Offset) + (2 * SizeOf(Float)))
    *this\VertexList()\w = 1.0     
 
    If *this\IsNormal : AddElement(*this\NormalList()) : EndIf  
    If *this\IsColor  : AddElement(*this\ColorList())  : EndIf
    If *this\IsUVMap
      If Not ListSize(*this\UVMapList()) : AddElement(*this\UVMapList()) : EndIf
      ResetList(*this\UVMapList())
      While NextElement(*this\UVMapList())
        AddElement(*this\UVMapList()\UV())
      Wend
    EndIf
  Next
EndProcedure


; Reset the Vertex list
Procedure Primitive_ResetVertexList(*this.Primitive_Template)
  ResetList(*this\VertexList())
  
  If *this\IsNormal : ResetList(*this\NormalList()) : EndIf  
  If *this\IsColor  : ResetList(*this\ColorList())  : EndIf
  If *this\IsUVMap      
    ResetList(*this\UVMapList())
    While NextElement(*this\UVMapList())
      ResetList(*this\UVMapList()\UV())
    Wend
  EndIf
    
EndProcedure

; Select a vertex i
Procedure Primitive_SelectVertex(*this.Primitive_Template, vID.l = #Null, UVMapID.l = #Null)
  Protected i.l
  SelectElement(*this\VertexList(), vID)
  
  If *this\IsNormal : SelectElement(*this\NormalList(), vID) : EndIf  
  If *this\IsColor  : SelectElement(*this\ColorList(), vID)  : EndIf
  If *this\IsUVMap      
    SelectElement(*this\UVMapList(), UVMapID)
    SelectElement(*this\UVMapList()\UV(), vID)
  EndIf  
EndProcedure

; Get the next vertex
Procedure Primitive_NextVertex(*this.Primitive_Template) 
  If *this\IsNormal : NextElement(*this\NormalList()) : EndIf  
  If *this\IsColor  : NextElement(*this\ColorList())  : EndIf
  If *this\IsUVMap : NextElement(*this\UVMapList()\UV()) : EndIf     
  
  ProcedureReturn NextElement(*this\VertexList())
EndProcedure

; Delete a vertex
Procedure Primitive_DeleteVertex(*this.Primitive_Template, vID.l = #Null)
  Protected i.l
  *this\p\SelectVertex(vID)
  
  DeleteElement(*this\VertexList())
  If *this\IsNormal : DeleteElement(*this\NormalList()) : EndIf  
  If *this\IsColor  : DeleteElement(*this\ColorList())  : EndIf
  If *this\IsUVMap : DeleteElement(*this\UVMapList()\UV()) : EndIf   
EndProcedure

; Clears vertex list
Procedure Primitive_ClearVertexList(*this.Primitive_Template)
  Protected i.l
  ClearList(*this\VertexList()) 
  If *this\IsNormal : ClearList(*this\NormalList()) : EndIf  
  If *this\IsColor  : ClearList(*this\ColorList())  : EndIf
  If *this\IsUVMap: ClearList(*this\UVMapList()\UV()): EndIf     
EndProcedure


; Set the normal coordinates for the Vertex
Procedure Primitive_SetNormal(*this.Primitive_Template, x.f, y.f, z.f)
  If Not *this\IsNormal : ProcedureReturn #False : EndIf
  *this\NormalList()\x = x
  *this\NormalList()\y = y
  *this\NormalList()\z = z
  *this\NormalList()\w = 0.0
  ProcedureReturn #True  
EndProcedure

; Set the color for the Vertex
Procedure Primitive_SetColor(*this.Primitive_Template, *Color.D3DXCOLOR = #Null)  
  If Not *this\IsColor : ProcedureReturn #False : EndIf
  *this\ColorList()\r = *Color\r
  *this\ColorList()\g = *Color\g
  *this\ColorList()\b = *Color\b
  *this\ColorList()\a = *Color\a
  ProcedureReturn #True  
EndProcedure


Procedure Primitive_AddUVMap(*this.Primitive_Template)
  If Not *this\IsUVMap : ProcedureReturn #False : EndIf
  Protected *tmpLL.Primitive_UV = *this\UVMapList()

   AddElement(*this\UVMapList())    
   CopyList(*tmpLL\UV(), *this\UVMapList()\UV())  

  *this\Stride + SizeOf(XMFLOAT2)
EndProcedure

; Set the uv coordinates for the vertex
Procedure Primitive_SetUV(*this.Primitive_Template, u.f, v.f)  
  If Not *this\IsUVMap : ProcedureReturn #False : EndIf
  *this\UVMapList()\UV()\x = u
  *this\UVMapList()\UV()\y = v 
  ProcedureReturn #True  
EndProcedure

; Get the number of Vertices in the Primitive
Procedure Primitive_VertexListSize(*this.Primitive_Template)
   ProcedureReturn ListSize(*this\VertexList())
EndProcedure

; Get the size in byte of a single vertex
Procedure Primitive_VertexSize(*this.Primitive_Template) 
   ProcedureReturn *this\Stride
EndProcedure
 

; Creates a new array of vertices from the lists and returns the pointer 
; Allocates new memory for the array. You must release this later
Procedure Primitive_GetVerticesArray(*this.Primitive_Template)
  
  If ListSize(*this\VertexList()) = 0: ProcedureReturn #False : EndIf  
  
  Protected newSize.i = *this\Stride * ListSize(*this\VertexList())  
  Protected *newArray = AllocateMemory(newSize), x.i = #Null, i.i = ListSize(*this\UVMapList())
  Protected *tmpLL.Primitive_UV 
  Protected Offset.l = SizeOf(XMFLOAT4)

  *this\p\ResetVertexList()
  While *this\p\NextVertex()
    
    CopyMemory(@*this\VertexList(), *newArray + (x * *this\Stride), SizeOf(XMFLOAT4))

    If *this\IsNormal
      CopyMemory(@*this\NormalList(), *newArray + (x * *this\Stride) + Offset, SizeOf(XMFLOAT4))    
    EndIf
    
    If *this\IsColor  
      If *this\IsNormal : Offset + SizeOf(XMFLOAT4) : EndIf        
      CopyMemory(@*this\ColorList(), *newArray + (x * *this\Stride) + Offset, SizeOf(D3DXCOLOR))     
    EndIf
    x + 1
  Wend
  
  x = #Null
  If *this\IsUVMap
    
    ResetList(*this\UVMapList())  
    While NextElement(*this\UVMapList())
      
      *tmpLL = *this\UVMapList()
      x = 1
      
      ResetList(*tmpLL\UV())
      While NextElement(*tmpLL\UV())
        
        CopyMemory(*this\UVMapList()\UV(), *newArray + (x * *this\Stride) - (i * SizeOf(XMFLOAT2)), SizeOf(XMFLOAT2))
   
        x + 1
      Wend
      i - 1
    Wend    
  EndIf
  
  ProcedureReturn *newArray
EndProcedure


; Add an index to the indices array
Procedure Primitive_AddIndex(*this.Primitive_Template, Index.l)  
  ProcedureReturn *this\p\AddIndicesArray(@Index)
EndProcedure



; Add a array off indices to the indices array
Procedure Primitive_AddIndicesArray(*this.Primitive_Template, *Indices, IndexCount.l = #Null)   
  For x = 0 To IndexCount
    AddElement(*this\IndexList())
    *this\IndexList() = PeekL(*Indices + (x * SizeOf(Long))) 
  Next 
  ProcedureReturn *this\IndexList()
EndProcedure


; Get the number of entrys in the indices array
Procedure Primitive_GetIndexCount(*this.Primitive_Template)    
  ProcedureReturn ListSize(*this\IndexList())
EndProcedure

; Reset the index list
Procedure Primitive_ResetIndex(*this.Primitive_Template)  
  NextElement(*this\IndexList())
EndProcedure

; Select a index entry by the index id
Procedure Primitive_SelectIndex(*this.Primitive_Template, iId.l)  
  SelectElement(*this\IndexList(), iId)
EndProcedure

; Next index entry
Procedure Primitive_NextIndex(*this.Primitive_Template)  
  NextElement(*this\IndexList())
EndProcedure

; Delete an index entry
Procedure Primitive_DeleteIndex(*this.Primitive_Template)  
  DeleteElement(*this\IndexList())
EndProcedure

; Clear the index list
Procedure Primitive_ClearIndexList(*this.Primitive_Template)  
  ClearList(*this\IndexList())
EndProcedure

; Set a specific index entry by the index id
Procedure Primitive_SetIndex(*this.Primitive_Template,  NewIndex.l)  
  *this\IndexList() = NewIndex
EndProcedure

; Get the selected index
Procedure Primitive_GetIndex(*this.Primitive_Template)  
  ProcedureReturn *this\IndexList() 
EndProcedure

; Get a new Array of Indicies
; Remember to  release it later
Procedure Primitive_GetIndexArray(*this.Primitive_Template)  
  Protected *newIndexArray = AllocateMemory(SizeOf(Long) * ListSize(*this\IndexList())), x.l = 0
  
  
  ResetList(*this\IndexList())
  While NextElement(*this\IndexList())
    
    PokeL(*newIndexArray + (x * SizeOf(Long)), *this\IndexList())
  
    x + 1
  Wend

  ProcedureReturn *newIndexArray
EndProcedure

; Release the Primitiv
Procedure Primitive_Release(*this.Primitive_Template)  
  ClearList(*this\VertexList()) 
  If *this\IsNormal : ClearList(*this\NormalList()) : EndIf
  If *this\IsColor : ClearList(*this\ColorList())  : EndIf
  
  If *this\IsUVMap
    ResetList(*this\UVMapList())
    While NextElement(*this\UVMapList())
      ClearList(*this\UVMapList()\UV()) 
    Wend
    ClearList(*this\UVMapList()) 
  EndIf 
  FreeMemory(*this)
EndProcedure


; Set the vertex topology
Procedure Primitive_SetTopology(*this.Primitive_Template, Topology.l)  
  *this\Topology =  Topology
EndProcedure

; Get the vertex topology
Procedure Primitive_GetTopology(*this.Primitive_Template)  
  ProcedureReturn *this\Topology
EndProcedure

; Get the vertex stride
Procedure Primitive_GetStride(*this.Primitive_Template)  
  ProcedureReturn *this\Stride
EndProcedure



;-//    Private procedures    //

;/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
;/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
;/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
;/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
;/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
;-//    DataSection    //
DataSection
  Primitive_Class:
  Data.i @Primitive_AddVertex()
  Data.i @Primitive_AddVerticesArray()
  Data.i @Primitive_ResetVertexList()
  Data.i @Primitive_SelectVertex()
  Data.i @Primitive_NextVertex()
  Data.i @Primitive_DeleteVertex()
  Data.i @Primitive_ClearVertexList()
  Data.i @Primitive_SetNormal()
  Data.i @Primitive_SetColor()
  Data.i @Primitive_AddUVMap()
  Data.i @Primitive_SetUV()
  Data.i @Primitive_VertexListSize()
  Data.i @Primitive_VertexSize()
  Data.i @Primitive_GetVerticesArray()
  Data.i @Primitive_AddIndex()
  Data.i @Primitive_AddIndicesArray()
  Data.i @Primitive_GetIndexCount()
  Data.i @Primitive_ResetIndex()
  Data.i @Primitive_SelectIndex()
  Data.i @Primitive_NextIndex()
  Data.i @Primitive_DeleteIndex()
  Data.i @Primitive_ClearIndexList()
  Data.i @Primitive_SetIndex()
  Data.i @Primitive_GetIndex()
  Data.i @Primitive_GetIndexArray()
  Data.i @Primitive_Release()
  Data.i @Primitive_SetTopology()
  Data.i @Primitive_GetTopology()
  Data.i @Primitive_GetStride()
EndDataSection










; IDE Options = PureBasic 5.20 beta 10 LTS (Windows - x64)
; CursorPosition = 54
; FirstLine = 10
; Folding = ------
; EnableXP
; EnableCompileCount = 0
; EnableBuildCount = 0